#ifndef SERIALPORTENGINE_H
#define SERIALPORTENGINE_H

#include <QObject>
#include <QSerialPort>
#include <QTimer>

#include "ComStackTypes.h"

class SerialPortInfo {
public:
    QString port = "";
    QString location = "";
    QString description = "";
    QString manufacturer  = "";
    QString serialNumber = "";
    QString vendor_id = "";
    QString product_id = "";
};

class SerialPortEngine : public QObject {
    Q_OBJECT
public:
    SerialPortEngine();
    ~SerialPortEngine();
    int connectDevice(const QString &name);
    void disConnectDevice();
    void receiveBytesConfirmation();

    enum ErrorCode {
        SERIAL_SUCCESS = 0,
        OBJECT_IS_NULL = -1,
        SERIAL_IS_CONNECTED = -2,
        SERIAL_IS_OCCUPIED = -3,
    };

    enum BreakTypeType {
        BREAK_INTERVAL = 0,
        BREAK_CRLF,
        BREAK_CR,
        BREAK_LF,
    };

    SerialPortEngine::BreakTypeType breakType() const { return break_type; }
    void setBreakType(SerialPortEngine::BreakTypeType type);

    void scanExistenceDevice();
    QStringList nameList() const;
    void updateSettings(const int baudRate, const int dataBits, const int parity, const int stopBits);
    void setFlowControl(const int flowCtrl);
    bool isOpened() const { return opened; }

signals:
    void receiveBytesIndication(const PduInfoType *pdu);

public slots:
    void sendMessage(const PduInfoType* pdu);
    void handleReadyRead();
    void handleTimeout();

private:
    QSerialPort *serialPort = nullptr;
    QTimer *timer = nullptr;
    int timer_ticks = 0;
    QByteArray bytes_buffer;
    int frame_interval = 10;

    QList<QByteArray> frame_list;
    const int frame_buffer_deepth = 1024;   // set max 1024 bytes for a frame
    const int frame_list_deepth = 8;        // set frame list max count
    int confirm_count = 0;
    void frameListIndication();

    BreakTypeType break_type = BREAK_CRLF;

    bool initialized = false;
    bool opened = false;
    QList<SerialPortInfo> serial_info_list;
};

#endif // SERIALPORTENGINE_H
